<html>
<head>
  <title>Dragdealer.js – drag provider, the good stuff</title>
  <meta charset="utf-8">
  <meta name="description" content="Drag-based JavaScript component, embracing endless UI solutions.">

  <link href="lib/jasmine.css" type="text/css" rel="stylesheet">
  <link href="lib/font-awesome/css/font-awesome.min.css" type="text/css" rel="stylesheet">
  <script src="lib/jquery-1.10.2.js"></script>
  <script src="lib/jquery.simulate.js"></script>
  <script src="lib/jasmine.js"></script>
  <script src="lib/jasmine-jsreporter.js"></script>
  <script src="lib/jasmine-html.js"></script>
  <script src="lib/jasmine-jquery.js"></script>

  <link href="src/dragdealer.css" type="text/css" rel="stylesheet">
  <script src="src/dragdealer.js"></script>

  <script src="spec/helpers.js"></script>
  <script src="spec/matchers.js"></script>
  <script src="spec/optionsSpec.js"></script>
  <script src="spec/draggingSpec.js"></script>
  <!--[if gt IE 9]><!-->
  <script src="spec/touchDraggingSpec.js"></script>
  <!--<![endif]-->
  <script src="spec/callbacksSpec.js"></script>
  <script src="spec/apiSpec.js"></script>
  <script src="spec/resizingSpec.js"></script>
  <script src="spec/eventsSpec.js"></script>
  <script src="spec/setup.js"></script>
  <script src="spec/browser-runner.js"></script>

  <link href="demo/style/index.css" type="text/css" rel="stylesheet">
  <link href="demo/style/jasmine-reporter.css" type="text/css" rel="stylesheet">
  <link href="demo/style/demos.css" type="text/css" rel="stylesheet">
  <script src="demo/script/index.js"></script>
  <script src="demo/script/demos.js"></script>
</head>
<body>
  <div id="main-slider" class="dragdealer">
    <div class="specs-tab">
      <ul class="specs-bullets"></ul>
      <p class="specs-summary"></p>
    </div>
    <div class="handle red-bar">
      <h1><strong>Dragdealer</strong>.js</h1>
    </div>
  </div>
  <div id="content">
    <div class="content-slides">
      <div class="slide demo">
        <div class="inner-wrapper">
          <div class="important">
            <p><strong>Jan 2014:</strong> Almost 4 years from the initial Dragdealer launch, a new version is released. For more details read the <a href="https://medium.com/p/370ff43bcb31">blog post</a> or check out the freshly baked <a href="https://github.com/skidding/dragdealer">GitHub repo.</a></p>
          </div>

          <h2>Drag-based JavaScript component, embracing endless UI solutions</h2>
          <p>2d dragging and tapping, mouse and touch, ~12KB. No dependency. <a href="https://github.com/skidding/dragdealer/blob/master/Gruntfile.js#L2-L44">Any browser.</a></p>
          <ul class="project-buttons">
            <li>
              <a href="https://github.com/skidding/dragdealer">
                <i class="fa fa-github"></i> source code
              </a>
            </li>
            <li>
              <a href="https://github.com/skidding/dragdealer/archive/master.zip">
                <i class="fa fa-cloud-download"></i> download
              </a>
            </li>
            <li>
              <a href="#demos" class="internal-link">
                <i class="fa fa-magic"></i> jump to demos
              </a>
            </li>
          </ul>

<pre class="code">
&lt;div id="demo-simple-slider" class="<strong>dragdealer</strong>"&gt;
  &lt;div class="<strong>handle</strong> red-bar"&gt;drag me&lt;/div&gt;
&lt;/div&gt;
</pre>
<pre class="code">
<strong>new Dragdealer</strong>('demo-simple-slider');
</pre>
          <div id="demo-simple-slider" class="dragdealer">
            <div class="handle red-bar">drag me</div>
          </div>

          <h3>JS API</h3>
          <p>Here are the options, callbacks and methods Dragdealer supports, but you can read the <a href="https://github.com/skidding/dragdealer/blob/master/src/dragdealer.js">source code</a> for more information.</p>

          <h4>Constructor</h4>
          <ul class="property-list">
            <li>
              <strong>Dragdealer(wrapper, options={})</strong>
              <span class="description">Accepts an id or a DOM reference for the wrapper element. See possible options below.</span>
            </li>
          </ul>

          <h4>Options</h4>
          <ul class="property-list">
            <li>
              <span class="type">bool</span>
              <strong>disabled</strong><span class="default">=false</span>
              <span class="description">Init Dragdealer in a disabled state. The handle will have a .disabled class.</span>
            </li>
            <li>
              <span class="type">bool</span>
              <strong>horizontal</strong><span class="default">=true</span>
              <span class="description">Enable horizontal dragging.</span>
            </li>
            <li>
              <span class="type">bool</span>
              <strong>vertical</strong><span class="default">=false</span>
              <span class="description">Enable vertical dragging.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>x</strong><span class="default">=0</span>
              <span class="description">Initial horizontal (left) position. Accepts a float number value between 0 and 1.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>y</strong><span class="default">=0</span>
              <span class="description">Initial vertical (top) position. Accepts a float number value between 0 and 1.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>steps</strong><span class="default">=0</span>
              <span class="description">Limit the positioning of the handle within the bounds of the wrapper, by defining a virtual grid made out of a number of equally-spaced steps. This restricts placing the handle anywhere in-between these steps. E.g. setting 3 steps to a regular slider will only allow you to move it to the left, to the right or exactly in the middle.</span>
            </li>
            <li>
              <span class="type">bool</span>
              <strong>snap</strong><span class="default">=false</span>
              <span class="description">When a number of steps is set, snap the position of the handle to its closest step instantly, even when dragging.</span>
            </li>
            <li>
              <span class="type">bool</span>
              <strong>slide</strong><span class="default">=true</span>
              <span class="description">Slide handle after releasing it, depending on the movement speed before the mouse/touch release.</span>
            </li>
            <li>
              <span class="type">bool</span>
              <strong>loose</strong><span class="default">=false</span>
              <span class="description">Loosen-up wrapper boundaries when dragging. This allows the handle to be *slightly* dragged outside the bounds of the wrapper, but slides it back to the margins of the wrapper upon release.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>top</strong><span class="default">=0</span>
              <span class="description">Top padding between the wrapper and the handle.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>bottom</strong><span class="default">=0</span>
              <span class="description">Bottom padding between the wrapper and the handle.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>left</strong><span class="default">=0</span>
              <span class="description">Left padding between the wrapper and the handle.</span>
            </li>
            <li>
              <span class="type">number</span>
              <strong>right</strong><span class="default">=0</span>
              <span class="description">Right padding between the wrapper and the handle.</span>
            </li>
            <li>
              <span class="type">fn</span>
              <strong>callback(x, y)</strong>
              <span class="description">Called when releasing handle, with the projected x, y position of the handle. Projected value means the value the slider will have after finishing a sliding animation, caused by either a step restriction or drag motion (see <em>steps</em> and <em>slide</em> options.)</span>
            </li>
            <li>
              <span class="type">fn</span>
              <strong>dragStopCallback(x, y)</strong>
              <span class="description">Same as callback(x,y) but only called after a drag motion, not after setting the step manually.</span>
            </li>
            <li>
              <span class="type">fn</span>
              <strong>dragStartCallback(x, y)</strong>
              <span class="description">Same as dragStopCallback(x,y) but called at the beginning of a drag motion and with the sliders initial x, y values.</span>
            </li>
            <li>
              <span class="type">fn</span>
              <strong>animationCallback(x, y)</strong>
              <span class="description">Called every animation loop, as long as the handle is being dragged or in the process of a sliding animation. The x, y positional values received by this callback reflect the exact position of the handle DOM element, which includes exceeding values (even negative values) when the <em>loose</em> option is set true.</span>
            </li>
            <li>
              <span class="type">string</span>
              <strong>handleClass</strong><span class="default">=handle</span>
              <span class="description">Custom class of handle element.</span>
            </li>
            <li>
              <span class="type">bool</span>
              <strong>css3</strong><span class="default">=true</span>
              <span class="description">Use css3 transform in modern browsers instead of absolute positioning.</span>
            </li>
            <li>
              <span class="type">fn</span>
              <strong>customRequestAnimationFrame</strong>
              <span class="description">Provide custom requestAnimationFrame function (used in tests).</span>
            </li>
            <li>
              <span class="type">fn</span>
              <strong>customCancelAnimationFrame</strong>
              <span class="description">Provide custom cancelAnimationFrame function (used in tests).</span>
            </li>
          </ul>

          <h4>Methods</h4>
          <ul class="property-list">
            <li>
              <strong>disable</strong>
              <span class="description">Disable dragging of a Dragdealer instance. Just as with the <em>disabled</em> option, the handle will receive a .disabled class</span>
            </li>
            <li>
              <strong>enable</strong>
              <span class="description">Enable dragging of a Dragdealer instance. The .disabled class of the handle will be removed.</span>
            </li>
            <li>
              <strong>reflow</strong>
              <span class="description">Recalculate the wrapper bounds of a Dragdealer instance, used when the wrapper is responsive and its parent container changed its size, or after changing the size of the wrapper directly.</span>
            </li>
            <li>
              <strong>getValue</strong>
              <span class="description">Get the value of a Dragdealer instance programatically. The value is returned as an [x, y] tuple and is the equivalent of the <em>projected</em> value returned by the regular callback, not animationCallback.</span>
            </li>
            <li>
              <strong>getStep</strong>
              <span class="description">Same as getValue, but the value returned is in step increments (see <em>steps</em> option)</span>
            </li>
            <li>
              <strong>setValue(x, y, snap=false)</strong>
              <span class="description">Set the value of a Dragdealer instance programatically. The 3rd parameter allows to snap the handle directly to the desired value, without any sliding transition.</span>
            </li>
            <li>
              <strong>setStep(x, y, snap=false)</strong>
              <span class="description">Same as setValue, but the value is received in step increments (see <em>steps</em> option)</span>
            </li>
          </ul>

          <h3 id="demos">Demos</h3>
          <p class="secondary">Some demos will use jQuery to manipulate surrounding elements. This is for keeping the examples as small as possible, Dragdealer doesn't have a jQuery or any other dependency.</p>

          <h4>Just a slider</h4>
          <p>A slider is just a user control, the power lies in the value it represents. For this reason the <strong>animationCallback</strong> is your biggest ally, with it you tie the user input to any visualization you can think of. This is the most boring example.</p>

<pre class="code">
new Dragdealer('just-a-slider', {
  <strong>animationCallback</strong>: function(x, y) {
    $('#just-a-slider .value').text(Math.round(<strong>x</strong> * 100));
  }
});
</pre>
          <div id="just-a-slider" class="dragdealer">
            <div class="handle red-bar">
              <span class="value"></span>%
            </div>
          </div>

          <h4>Content scroller</h4>
          <p>Controlling a different element is a straightforward use-case for Dragdealer. It's basic math. Let's spice it up with some vertical movement.</p>

<pre class="code">
var availHeight = $('.content-body').outerHeight() -
                  $('.content-mask').outerHeight();
new Dragdealer('content-scroller', {
  horizontal: false,
  <strong>vertical: true,</strong>
  <strong>yPrecision: availHeight,</strong>
  animationCallback: function(x, y) {
    $('.content-body').css('margin-top', -<strong>y</strong> * availHeight);
  }
});
</pre>

          <div class="content-scroller">
            <div id="content-scroller" class="dragdealer">
              <div class="handle red-bar">
                <span class="value"><i class="fa fa-bars"></i></span>
              </div>
            </div>
            <div class="content-mask">
              <div class="content-body">
<p>It was all a dream<br>
I used to read Word Up magazine<br>
Salt 'n' Pepa and Heavy D up in the limousine<br>
Hangin pictures on my wall<br>
Every Saturday Rap Attack, Mr. Magic, Marley Marl<br>
I let my tape rock 'til my tape popped<br>
Smoking weed and Bambu, sipping on Private Stock<br>
Way back, when I had the red and black lumberjack<br>
With the hat to match<br>
Remember Rappin Duke? duh-ha, duh-ha<br>
You never thought that hip hop would take it this far<br>
Now I'm in the limelight cause I rhyme tight<br>
Time to get paid, blow up like the World Trade<br>
Born sinner, the opposite of a winner<br>
Remember when I used to eat sardines for dinner<br>
Peace to Ron G, Brucey B, Kid Capri<br>
Funkmaster Flex, Lovebug Starski (wassup)<br>
I'm blowing up like you thought I would<br>
Call the crib, same number same hood (that's right)<br>
It's all good (it's all good)<br>
And if you don't know, now you know, nigga</p>

<p>I made the change from a common thief<br>
To up close and personal with Robin Leach<br>
And I'm far from cheap, I smoke skunk with my peeps all day<br>
Spread love, it's the Brooklyn way<br>
The Moet and Alizé keep me pissy<br>
Girls used to diss me<br>
Now they write letters cause they miss me<br>
I never thought it could happen, this rapping stuff<br>
I was too used to packing gats and stuff<br>
Now honeys play me close like butter play toast<br>
From the Mississippi down to the east coast<br>
Condos in Queens, indo for weeks<br>
Sold out seats to hear Biggie Smalls speak<br>
Living life without fear<br>
Putting 5 karats in my baby girl's ears<br>
Lunches, brunches, interviews by the pool<br>
Considered a fool cause I dropped out of high school<br>
Stereotypes of a black male misunderstood<br>
And it's still all good<br>
Uh...and if you don't know, now you know, nigga</p>

<p>Super Nintendo, Sega Genesis<br>
When I was dead broke, man I couldn't picture this<br>
50-inch screen, money green leather sofa<br>
Got two rides, a limousine with a chauffeur<br>
Phone bill about two G's flat<br>
No need to worry, my accountant handles that<br>
And my whole crew is lounging<br>
Celebrating every day, no more public housing<br>
Thinking back on my one-room shack<br>
Now my mom pimps a Ac with minks on her back<br>
And she loves to show me off, of course<br>
Smiles every time my face is up in The Source<br>
We used to fuss when the landlord dissed us<br>
No heat, wonder why Christmas missed us<br>
Birthdays was the worst days<br>
Now we sip champagne when we thirst-ay<br>
Uh, damn right I like the life I live<br>
Cause I went from negative to positive<br>
And it's all</p>

<p>...and if you don't know, now you know, niggaaa</p>
              </div>
            </div>
          </div>

          <p>The <em>yPrecision</em> option adjusts the (vertical) granularity of the callback values. It is useful when controlling an element larger than the Dragdealer wrapper, in offering a smooth transition at the end.</p>

          <p class="secondary">Please note that this is not a complete solution for a custom scrollbar, nor does it try to be. You could make the content scrollable with a few lines of code but I for one think generic <em>custom scrollbars</em> are sent from hell.</p>

          <h4><em>"slide to unlock"</em></h4>
          <p>This is how this project started, somebody wanted an iPhone-like slider. Classic.</p>

<pre class="code">
new Dragdealer('slide-to-unlock-old', {
  <strong>steps: 2,</strong>
  callback: function(x, y) {
    // Only 0 and 1 are the possible values because of "steps: 2"
    <strong>if (x) {</strong>
      this.disable();
      $('#slide-to-unlock-old').fadeOut();
    }
  }
});
</pre>
          <div class="slide-to-unlock old-slider">
            <div id="slide-to-unlock-old" class="dragdealer">
              <div class="slide-text">slide to unlock</div>
              <div class="handle"></div>
            </div>
          </div>

          <p>But the iPhone changed since then, iOS has a different start screen. Let's see how hard would it be to reproduce it.</p>

<pre class="code">
new Dragdealer('slide-to-unlock-new', {
  <strong>x: 1,</strong>
  <strong>steps: 2,</strong>
  <strong>loose: true,</strong>
  callback: function(x, y) {
    // Only 0 and 1 are the possible values because of "steps: 2"
    <strong>if (!x) {</strong>
      this.disable();
      $('#slide-to-unlock-new').fadeOut();
    }
  }
});
</pre>
          <div class="slide-to-unlock new-slider">
            <div id="slide-to-unlock-new" class="dragdealer">
              <div class="handle">
                <div class="slide-text"><i class="fa fa-angle-right"></i> slide to unlock</div>
              </div>
            </div>
          </div>
          <p>By no means do these demos try to be exact replicas, but merely to show the flexibility of Dragdealer.</p>

          <p class="secondary">The latter example has the handle (the dragging object) bigger than the wrapper, which in turn has <em>overflow: hidden;</em> to mask the bigger handle surface. You should check out the HTML and CSS to understand these examples better.</p>

          <h4>Image carousel</h4>
          <p>Let's kick it up a notch. How about a <strong>touch-ready image carousel</strong>... piece of cake. The entire string of images will be the draggable handle, masked by a wrapper the size of a single image (a slide.)</p>

<pre class="code">
new Dragdealer('image-carousel', {
  <strong>steps: 4,
  speed: 0.3,
  loose: true,
  requestAnimationFrame: true</strong>
});
</pre>
          <div id="image-carousel" class="dragdealer">
            <div class="handle">
              <div class="slide img1">
                <div class="info">
                  <p class="title">Aston Martin DB4</p>
                  <p class="description"><strong>1959</strong> — 3.7L, 240hp</p>
                </div>
              </div>
              <div class="slide img2">
                <div class="info">
                  <p class="title">Mercedes-Benz 300SL</p>
                  <p class="description"><strong>1956</strong> — 2996cc, 212-222hp</p>
                </div>
              </div>
              <div class="slide img3">
                <div class="info">
                  <p class="title">Jaguar E-Type</p>
                  <p class="description"><strong>1966</strong> — 3.8L, 265bhp</p>
                </div>
              </div>
              <div class="slide img4">
                <div class="info">
                  <p class="title">Maserati A6</p>
                  <p class="description"><strong>1950</strong> — 2L, 120bhp</p>
                </div>
              </div>
            </div>
          </div>

          <p>The <em>speed</em> option makes Dragdealer snappier, by speeding up the sliding animations. It takes up values between 0 and 1 and it defaults to 0.1.</p>

          <h4>Interactive canvas mask</h4>
          <p>With Dragdealer you can go from creating a simple slider to an entire website. I'm only saying this because I've seen more than a few examples of full-window implementations.</p>

<pre class="code">
var canvasMask = new Dragdealer('canvas-mask', {
  x: 0,
  // Start in the bottom-left corner
  y: 1,
  <strong>vertical: true,
  speed: 0.2,
  loose: true,
  requestAnimationFrame: true</strong>
});

// Bind event on the wrapper element to prevent it when a drag has been made
// between mousedown and mouseup (by stopping propagation from handle)
$('#canvas-mask').on('click', '.menu a', function(e) {
  e.preventDefault();
  var anchor = $(e.currentTarget);
  <strong>canvasMask.setValue(anchor.data('x'), anchor.data('y'));</strong>
});
</pre>
          <div id="canvas-mask" class="dragdealer">
            <div class="handle">
              <div class="page">
                <p class="menu">
                  <a href="#" data-x="0" data-y="1">Two-dimensional</a> |
                  <a href="#" data-x="1" data-y="1">Elastic</a> |
                  <a href="#" data-x="1" data-y="0">Interactive</a> |
                  <strong>Open</strong>
                </p>
                <p class="body">
                  Dragdealer is <strong>open source</strong>, <br >
                  see you on <a href="https://github.com/skidding/dragdealer">GitHub</a>
                </p>
              </div>
              <div class="page">
                <p class="menu">
                  <a href="#" data-x="0" data-y="1">Two-dimensional</a> |
                  <a href="#" data-x="1" data-y="1">Elastic</a> |
                  <strong>Interactive</strong> |
                  <a href="#" data-x="0" data-y="0">Open</a>
                </p>
                <p class="body">
                  The dragged surface can host <strong>rich content</strong>, <br>
                  including links for scrolling inside itself
                </p>
              </div>
              <div class="page">
                <p class="menu">
                  <strong>Two-dimensional</strong> |
                  <a href="#" data-x="1" data-y="1">Elastic</a> |
                  <a href="#" data-x="1" data-y="0">Interactive</a> |
                  <a href="#" data-x="0" data-y="0">Open</a>
                </p>
                <p class="body">
                  The masked content can be discovered through <br>
                  both <strong>horizontal and vertical dragging</strong>
                </p>
              </div>
              <div class="page">
                <p class="menu">
                  <a href="#" data-x="0" data-y="1">Two-dimensional</a> |
                  <strong>Elastic</strong> |
                  <a href="#" data-x="1" data-y="0">Interactive</a> |
                  <a href="#" data-x="0" data-y="0">Open</a>
                </p>
                <p class="body">
                  The surface boundaries have an <strong>elastic ease</strong> and <br>
                  the corners can be slightly pulled inwards
                </p>
              </div>
            </div>
          </div>

          <p class="secondary">The previous version of Dragdealer had a major drawback for this use-case: buttons and links from inside the handle (which is the entire content) would not clickable on touch devices anymore, once Dragdealer was initialized. That is <a href="https://github.com/skidding/dragdealer/pull/7">fixed</a> now.</p>

          <p class="disclaimer">Dragdealer is just a drag component, the rest is up to you.</p>

          <p>&copy; 2010+ <a href="https://twitter.com/skidding">@skidding</a> — Best regards</p>
        </div>
      </div>
      <div class="slide specs">
        <!-- Jasmine reporter goes here -->
      </div>
    </div>
  </div>
</body>
</html>
